/*
 * Copyright (c) 2025 Huawei Technologies Co., Ltd.
 * openUBMC is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *         http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

#include <gtest/gtest.h>

#include <memory>
#include <string>

#include <mc/common.h>
#include <mc/memory.h>

#include "../../../../../drivers/pcie_nic_card/wx/interface/board.h"

namespace {

// Test fixture
class board_test : public ::testing::Test {
protected:
    void SetUp() override {
        m_board = mc::make_shared<dev::Board>();
    }

    void TearDown() override {
        m_board.reset();
    }

    mc::shared_ptr<dev::Board> m_board;
};

// ========== replace_dynamic_property 测试 ==========

TEST_F(board_test, replace_dynamic_property_replaces_slot_placeholder) {
    mc::mutable_dict object;
    mc::mutable_dict board_obj;
    board_obj["Slot"] = std::string("${Slot}");
    object["bmc.dev.Board"] = board_obj;

    mc::dict connector{{"Slot", static_cast<uint8_t>(5)}};

    m_board->replace_dynamic_property(object, connector);

    auto updated_obj = object["bmc.dev.Board"].as<mc::mutable_dict>();
    EXPECT_EQ(updated_obj["Slot"].as<uint8_t>(), 5);
}

TEST_F(board_test, replace_dynamic_property_does_not_replace_non_placeholder) {
    mc::mutable_dict object;
    mc::mutable_dict board_obj;
    // Slot 如果不是 "${Slot}" 占位符，则不会被替换
    board_obj["Slot"] = std::string("10");
    object["bmc.dev.Board"] = board_obj;

    mc::dict connector{{"Slot", static_cast<uint8_t>(5)}};

    m_board->replace_dynamic_property(object, connector);

    auto updated_obj = object["bmc.dev.Board"].as<mc::mutable_dict>();
    // 由于不是 "${Slot}" 占位符，应该保持原值
    EXPECT_EQ(updated_obj["Slot"].as<std::string>(), "10");
}

TEST_F(board_test, replace_dynamic_property_does_not_replace_string_slot) {
    mc::mutable_dict object;
    mc::mutable_dict board_obj;
    // Slot 如果是字符串但不是 "${Slot}"，则不会被替换
    board_obj["Slot"] = std::string("Slot5");
    object["bmc.dev.Board"] = board_obj;

    mc::dict connector{{"Slot", static_cast<uint8_t>(5)}};

    m_board->replace_dynamic_property(object, connector);

    auto updated_obj = object["bmc.dev.Board"].as<mc::mutable_dict>();
    // 由于不是 "${Slot}" 占位符，应该保持原值
    EXPECT_EQ(updated_obj["Slot"].as<std::string>(), "Slot5");
}

TEST_F(board_test, replace_dynamic_property_handles_missing_slot) {
    mc::mutable_dict object;
    mc::mutable_dict board_obj;
    // 没有 Slot 字段
    object["bmc.dev.Board"] = board_obj;

    mc::dict connector{{"Slot", static_cast<uint8_t>(5)}};

    // 应该不会崩溃
    EXPECT_NO_THROW(m_board->replace_dynamic_property(object, connector));
}

TEST_F(board_test, replace_dynamic_property_handles_different_slot_values) {
    mc::mutable_dict object;
    mc::mutable_dict board_obj;
    board_obj["Slot"] = std::string("${Slot}");
    object["bmc.dev.Board"] = board_obj;

    mc::dict connector{{"Slot", static_cast<uint8_t>(10)}};

    m_board->replace_dynamic_property(object, connector);

    auto updated_obj = object["bmc.dev.Board"].as<mc::mutable_dict>();
    EXPECT_EQ(updated_obj["Slot"].as<uint8_t>(), 10);
}

TEST_F(board_test, replace_dynamic_property_preserves_other_properties) {
    mc::mutable_dict object;
    mc::mutable_dict board_obj;
    board_obj["Slot"] = std::string("${Slot}");
    board_obj["OtherProperty"] = std::string("OtherValue");
    object["bmc.dev.Board"] = board_obj;

    mc::dict connector{{"Slot", static_cast<uint8_t>(5)}};

    m_board->replace_dynamic_property(object, connector);

    auto updated_obj = object["bmc.dev.Board"].as<mc::mutable_dict>();
    EXPECT_EQ(updated_obj["Slot"].as<uint8_t>(), 5);
    EXPECT_EQ(updated_obj["OtherProperty"].as<std::string>(), "OtherValue");
}

TEST_F(board_test, replace_dynamic_property_handles_empty_board_obj) {
    mc::mutable_dict object;
    mc::mutable_dict board_obj;
    object["bmc.dev.Board"] = board_obj;

    mc::dict connector{{"Slot", static_cast<uint8_t>(5)}};

    // 应该不会崩溃
    EXPECT_NO_THROW(m_board->replace_dynamic_property(object, connector));
}

TEST_F(board_test, replace_dynamic_property_handles_multiple_replacements) {
    mc::mutable_dict object;
    mc::mutable_dict board_obj;
    board_obj["Slot"] = std::string("${Slot}");
    object["bmc.dev.Board"] = board_obj;

    // 第一次替换
    mc::dict connector1{{"Slot", static_cast<uint8_t>(5)}};
    m_board->replace_dynamic_property(object, connector1);
    auto updated_obj1 = object["bmc.dev.Board"].as<mc::mutable_dict>();
    EXPECT_EQ(updated_obj1["Slot"].as<uint8_t>(), 5);

    // 第二次替换（需要重新设置占位符）
    board_obj["Slot"] = std::string("${Slot}");
    object["bmc.dev.Board"] = board_obj;
    mc::dict connector2{{"Slot", static_cast<uint8_t>(10)}};
    m_board->replace_dynamic_property(object, connector2);
    auto updated_obj2 = object["bmc.dev.Board"].as<mc::mutable_dict>();
    EXPECT_EQ(updated_obj2["Slot"].as<uint8_t>(), 10);
}

} // namespace

